#region Copyright (c) 2006-2009 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2009 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Widgetsphere.Generator.Models;

namespace Widgetsphere.Generator.Forms
{
	public partial class ImportVerificationForm : Form
	{
		private Widgetsphere.Generator.Models.Database _currentDatabase;
		private Widgetsphere.Generator.Models.Database _newDatabase;

		public ImportVerificationForm()
		{
			InitializeComponent();
		}

		internal ImportModelSettings Populate(Widgetsphere.Generator.Models.Database currentDatabase, Widgetsphere.Generator.Models.Database newDatabase)
		{
			ImportModelSettings retval = new ImportModelSettings();

			_currentDatabase = currentDatabase;
			_newDatabase = newDatabase;
			this.Populate();

			retval.OverridePrimaryKey = chkSettingPK.Checked;
			return retval;
		}

		private void Populate()
		{
			try
			{
				this.treeView1.Nodes.Clear();
				TreeNode tableParentNode = this.treeView1.Nodes[this.treeView1.Nodes.Add(new TreeNode("Tables"))];
				TreeNode relationshipParentNode = this.treeView1.Nodes[this.treeView1.Nodes.Add(new TreeNode("Relations"))];

				this.PopulateDataSchema(tableParentNode);
				this.PopulateRelationships(relationshipParentNode);

			}
			catch (Exception ex)
			{				
				throw;
			}
		}

		public int GetChangeCount()
		{
			return CountChanges(treeView1.Nodes);
		}

		private void PopulateDataSchema(TreeNode parentNode)
		{
			try
			{
				SortedList<string, DataTreeItem> Tables = new SortedList<string, DataTreeItem>();

				//Current Tables
				foreach (Table t in _currentDatabase.Tables)
				{
					DataTreeItem dti = new DataTreeItem(t.Name);					
					if (_newDatabase.Tables.Contains(t.Name))
						dti.Name = _newDatabase.Tables[t.Name].Name;

					//Check for deleted status
					if (!_newDatabase.Tables.Contains(t.Name))
						dti.State = DataTreeItem.DataTreeItemStateConstants.Delete;
					else if (_newDatabase.Tables[t.Name].Name != t.Name)
						dti.State = DataTreeItem.DataTreeItemStateConstants.Modified;
					else if (_newDatabase.Tables[t.Name].GetColumns().CorePropertiesHash != t.GetColumns().CorePropertiesHash)
						dti.State = DataTreeItem.DataTreeItemStateConstants.Modified;

					Tables.Add(t.Name.ToLower(), dti);
				}

				//Added Tables
				foreach (Table t in _newDatabase.Tables)
				{
					if (!_currentDatabase.Tables.Contains(t.Name))
						Tables.Add(t.Name.ToLower(), new DataTreeItem(t.Name, DataTreeItem.DataTreeItemStateConstants.Added));
				}

				//Now add to tree
				foreach (string tableKey in Tables.Keys)
				{
					TreeNode tableNode = new TreeNode(Tables[tableKey].Name);
					tableNode.Tag = Tables[tableKey];
					if (Tables[tableKey].State == DataTreeItem.DataTreeItemStateConstants.Added)
						tableNode.ForeColor = Color.Green;
					if (Tables[tableKey].State == DataTreeItem.DataTreeItemStateConstants.Delete)
						tableNode.ForeColor = Color.Red;
					if (Tables[tableKey].State == DataTreeItem.DataTreeItemStateConstants.Modified)
						tableNode.ForeColor = Color.Blue;

					parentNode.Nodes.Add(tableNode);

					Table oldTable = _currentDatabase.Tables[tableKey];
					Table newTable = _newDatabase.Tables[tableKey];
					if (oldTable == null) oldTable = new Table(_currentDatabase.Root);
					if (newTable == null) newTable = new Table(_newDatabase.Root);

					//Create list of all columns (new and old)
					SortedList<string, DataTreeItem> columns = new SortedList<string, DataTreeItem>();
					foreach (Reference r in oldTable.Columns)
					{
						Column column = (Column)r.Object;
						DataTreeItem dti = new DataTreeItem(column.Name);

						//Check for deleted status
						if (_newDatabase.Tables.Contains(Tables[oldTable.Name.ToLower()].Name))
						{
							if (!_newDatabase.Tables[Tables[oldTable.Name.ToLower()].Name].GetColumns().Contains(column.Name))
								dti.State = DataTreeItem.DataTreeItemStateConstants.Delete;
							else if (_newDatabase.Tables[Tables[oldTable.Name.ToLower()].Name].GetColumns()[column.Name].CorePropertiesHash != column.CorePropertiesHash)
								dti.State = DataTreeItem.DataTreeItemStateConstants.Modified;
						}

						columns.Add(column.Name.ToLower(), dti);

					}

					//Added Columns
					if (oldTable.Name == "")
					{
						foreach (Column column in _newDatabase.Tables[tableKey].GetColumns())
						{
							columns.Add(column.Name.ToLower(), new DataTreeItem(column.Name, DataTreeItem.DataTreeItemStateConstants.Added));
						}
					}
					else
					{
						if (_newDatabase.Tables.Contains(Tables[oldTable.Name.ToLower()].Name))
						{
							foreach (Column column in _newDatabase.Tables[Tables[oldTable.Name.ToLower()].Name].GetColumns())
							{
								if (!_currentDatabase.Tables[Tables[oldTable.Name.ToLower()].Name].GetColumns().Contains(column.Name))
									columns.Add(column.Name.ToLower(), new DataTreeItem(column.Name, DataTreeItem.DataTreeItemStateConstants.Added));
							}
						}
					}

					//Now load columns into tree
					if (_newDatabase.Tables.Contains(oldTable.Name))
					{
						foreach (string columnKey in columns.Keys)
						{
							TreeNode columnNode = new TreeNode(columns[columnKey].Name);
							if (columns[columnKey].State == DataTreeItem.DataTreeItemStateConstants.Added)
								columnNode.ForeColor = Color.Green;
							if (columns[columnKey].State == DataTreeItem.DataTreeItemStateConstants.Delete)
								columnNode.ForeColor = Color.Red;
							if (columns[columnKey].State == DataTreeItem.DataTreeItemStateConstants.Modified)
								columnNode.ForeColor = Color.Blue;

							columnNode.Tag = columns[columnKey];
							tableNode.Nodes.Add(columnNode);
						}
					}

				}

				this.BrandNodes(parentNode.Nodes);

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		private void PopulateRelationships(TreeNode parentNode)
		{
			try
			{
				Random rnd = new Random();
				SortedList<string, DataTreeItem> relationList = new SortedList<string, DataTreeItem>();

				//Current Tables
				foreach (Table t in _currentDatabase.Tables)
				{
					//Remove invalid links. Something is very wrong
					RelationCollection relationCollection = t.GetRelations();
					for (int ii = relationCollection.Count - 1; ii >= 0; ii--)
					{
						Relation relationshipItem = relationCollection[ii];
						int errorCount = 0;
						foreach (ColumnRelationship relationshipLinkItem in relationshipItem.ColumnRelationships)
						{
							if ((relationshipLinkItem.ChildColumnRef == null) || (relationshipLinkItem.ParentColumnRef == null))
								errorCount++;
						}
						if (errorCount > 0) t.Relationships.RemoveAt(ii);
					}
					//Remove Errors

					//If the table exists in the new graph...
					foreach (Relation relation in relationCollection)
					{
						Table t2 = _newDatabase.Tables[t.Name];
						DataTreeItem dti = new DataTreeItem(relation.RoleName);
						dti.Name = relation.ToLongString();
						if (t2 == null)
						{
							//The table was removed so the relationship was removed
							dti.State = DataTreeItem.DataTreeItemStateConstants.Delete;
						}
						else
						{
							//If the name changed then it was modified							
							Relation[] r2List = t2.GetRelations().GetFromMatch(relation);
							if (r2List.Length == 0)
							{
								dti.State = DataTreeItem.DataTreeItemStateConstants.Delete;
							}
							else if (r2List.Length == 1)
							{
								if (r2List[0].RoleName != relation.RoleName)
									dti.State = DataTreeItem.DataTreeItemStateConstants.Modified;
							}
							else if (r2List.Length > 1)
							{
								//There are multiple relationships for this table/column combination
								bool found = false;
								foreach (Relation r2 in r2List)
								{
									#region OLD CODE
									//if (r2.RoleName == relation.RoleName) found = true;
									//string parentTableName1 = ((Table)r2.ParentTableRef.Object).Name;
									//string parentTableName2 = ((Table)relation.ParentTableRef.Object).Name;

									//SortedDictionary<string, ColumnRelationship> list1 = new SortedDictionary<string,ColumnRelationship>();
									//foreach (ColumnRelationship cr in r2.ColumnRelationships)
									//{
									//  list1.Add(((Column)cr.ChildColumnRef.Object).Name, cr);
									//}

									//SortedDictionary<string, ColumnRelationship> list2 = new SortedDictionary<string, ColumnRelationship>();
									//foreach (ColumnRelationship cr in relation.ColumnRelationships)
									//{
									//  list2.Add(((Column)cr.ChildColumnRef.Object).Name, cr);
									//}

									//string parentColName1 = "";
									//foreach (string key in list1.Keys)
									//{
									//  parentColName1 += key;
									//}

									//string parentColName2 = "";
									//foreach (string key in list2.Keys)
									//{
									//  parentColName2 += key;
									//}

									////string parentCol
									//if ((parentTableName1 == parentTableName2) && (parentColName1 == parentColName2))
									//  found = true;
									#endregion

									if (r2.Equals(relation)) found = true;

								}
								if (!found)
									dti.State = DataTreeItem.DataTreeItemStateConstants.Modified;
							}

						}

						//If there is a duplicate then add a FAKE ROLE to it
						if (relationList.ContainsKey(relation.ToLongString().ToLower()))
						{
							relation.RoleName = "ROLE" + rnd.Next(10000, 100000);
							relationList.Add(relation.ToLongString().ToLower(), dti);
						}
						else
						{
							relationList.Add(relation.ToLongString().ToLower(), dti);
						}
						
					}
				}

				//Added Relationships
				foreach (Table t in _newDatabase.Tables)
				{
					foreach (Reference reference in t.Relationships)
					{
						Relation r = (Relation)reference.Object;
						string relationName = r.ToLongString();
						if (_currentDatabase.Tables.Contains(t.Name))
						{
							//If the old model has this table
							Table t2 = _currentDatabase.Tables[t.Name];
							if ((t2 != null) && (t2.GetRelations().GetFromMatch(r).Length == 0))
								relationList.Add(relationName.ToLower(), new DataTreeItem(relationName, DataTreeItem.DataTreeItemStateConstants.Added));
						}
						else
						{
							//Table and Relation not in old model
							if (!relationList.ContainsKey(relationName.ToLower()))
							{
								relationList.Add(relationName.ToLower(), new DataTreeItem(relationName, DataTreeItem.DataTreeItemStateConstants.Added));
							}
							else
							{
								int loop = 1;
								while (relationList.ContainsKey((relationName + "_RELATION" + loop).ToLower()))
								{
									loop++;
								}
								relationName += "_RELATION" + loop;
								relationList.Add(relationName.ToLower(), new DataTreeItem(relationName, DataTreeItem.DataTreeItemStateConstants.Added));
							}
						}
					}
				}

				//Now add to tree
				foreach (string relationKey in relationList.Keys)
				{
					TreeNode relationNode = new TreeNode(relationList[relationKey].Name);
					relationNode.Tag = relationList[relationKey];
					if (relationList[relationKey].State == DataTreeItem.DataTreeItemStateConstants.Added)
						relationNode.ForeColor = Color.Green;
					if (relationList[relationKey].State == DataTreeItem.DataTreeItemStateConstants.Delete)
						relationNode.ForeColor = Color.Red;
					if (relationList[relationKey].State == DataTreeItem.DataTreeItemStateConstants.Modified)
						relationNode.ForeColor = Color.Blue;

					parentNode.Nodes.Add(relationNode);
				}

				this.BrandNodes(parentNode.Nodes);

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		private void BrandNodes(TreeNodeCollection nodeList)
		{
			foreach (TreeNode node in nodeList)
			{
				if (((DataTreeItem)node.Tag).State == DataTreeItem.DataTreeItemStateConstants.Added)
					node.Text += " (Added)";
				else if (((DataTreeItem)node.Tag).State == DataTreeItem.DataTreeItemStateConstants.Delete)
					node.Text += " (Deleted)";
				else if (((DataTreeItem)node.Tag).State == DataTreeItem.DataTreeItemStateConstants.Modified)
					node.Text += " (Modified)";

				this.BrandNodes(node.Nodes);
			}
		}

		private void chkChangesOnly_Click(object sender, System.EventArgs e)
		{
			this.Populate();

			//If checked then remove all unchanged nodes to leave changed onese
			if (chkChangesOnly.Checked)
			{
				foreach (TreeNode node in this.treeView1.Nodes)
					this.RemoveUnchanged(node.Nodes);
			}
		}

		private void RemoveUnchanged(TreeNodeCollection nodeList)
		{
			List<TreeNode> delList = new List<TreeNode>();
			foreach (TreeNode node in nodeList)
			{
				if (((DataTreeItem)node.Tag).State == DataTreeItem.DataTreeItemStateConstants.Unchanged)
				{
					delList.Add(node);
				}
				RemoveUnchanged(node.Nodes);
			}

			foreach (TreeNode node in delList)
			{
				this.treeView1.Nodes.Remove(node);
			}
		}

		private int CountChanges(TreeNodeCollection nodeList)
		{
			int retval = 0;
			foreach (TreeNode node in nodeList)
			{
				if (node.Tag != null)
				{
					if (((DataTreeItem)node.Tag).State != DataTreeItem.DataTreeItemStateConstants.Unchanged)
						retval++;					
				}
				retval += CountChanges(node.Nodes);
			}
			return retval;
		}

		#region Event Handlers

		private void cmdOK_Click(object sender, System.EventArgs e)
		{
			this.DialogResult = DialogResult.OK;
			this.Close();
		}

		private void cmdCancel_Click(object sender, System.EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		#endregion

		#region DataTreeItem

		private class DataTreeItem
		{
			public enum DataTreeItemStateConstants
			{
				Unchanged = 0,
				Added = 1,
				Delete = 2,
				Modified = 3,
			}

			public string Name = "";
			public DataTreeItemStateConstants State = DataTreeItemStateConstants.Unchanged;

			public DataTreeItem(string name)
			{
				this.Name = name;
			}

			public DataTreeItem(string name, DataTreeItemStateConstants state)
				: this(name)
			{
				this.State = state;
			}

		}

		#endregion

	}
}